package pluginUtils;

import sliceformUtils.CoupleDAngles;
import sliceformUtils.Rotable;


// Cartesian coordinates in 3 dimensions
public class Pos3D implements Rotable<Pos3D>{
	
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		long temp;
		temp = Double.doubleToLongBits(x);
		result = prime * result + (int) (temp ^ (temp >>> 32));
		temp = Double.doubleToLongBits(y);
		result = prime * result + (int) (temp ^ (temp >>> 32));
		temp = Double.doubleToLongBits(z);
		result = prime * result + (int) (temp ^ (temp >>> 32));
		return result;
	}
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Pos3D other = (Pos3D) obj;
		if (Double.doubleToLongBits(x) != Double.doubleToLongBits(other.x))
			return false;
		if (Double.doubleToLongBits(y) != Double.doubleToLongBits(other.y))
			return false;
		if (Double.doubleToLongBits(z) != Double.doubleToLongBits(other.z))
			return false;
		return true;
	}

	static public final Pos3D ZERO=new Pos3D(0,0,0);
	protected double x,y,z;

	/**
	 * @param x
	 * @param y
	 * @param z
	 */
	public Pos3D(double x, double y, double z) {
		super();
		this.x = x;
		this.y = y;
		this.z = z;
	}
	public Pos3D(Pos3D X){
		this.x=X.x; 
		this.y=X.y; 
		this.z=X.z; 
	}

	/**
	 * @return the x
	 */
	public double getX() {
		return x;
	}

	/**
	 * @param x the x to set
	 */
	public void setX(double x) {
		this.x = x;
	}

	/**
	 * @return the y
	 */
	public double getY() {
		return y;
	}

	/**
	 * @param y the y to set
	 */
	public void setY(double y) {
		this.y = y;
	}

	/**
	 * @return the z
	 */
	public double getZ() {
		return z;
	}

	/**
	 * @param z the z to set
	 */
	public void setZ(double z) {
		this.z = z;
	} 
	
	public static double distance(Pos3D X1,Pos3D X2){
		double d=(X1.x-X2.x)*(X1.x-X2.x); 
		d+=(X1.y-X2.y)*(X1.y-X2.y); 
		d+=(X1.z-X2.z)*(X1.z-X2.z);
		return Math.sqrt(d); 
	}
	
	public static Pos3D add(Pos3D a,Pos3D b){
		return new Pos3D(a.x+b.x,a.y+b.y,a.z+b.z); 
	}
	
	public static Pos3D sub(Pos3D a,Pos3D b){
		return new Pos3D(a.x-b.x,a.y-b.y,a.z-b.z); 
	}
	
	public static Pos3D mul(Pos3D p,double a){
		return new Pos3D(a*p.x,a*p.y,a*p.z); 
	}
	
	public static Pos3D middle(Pos3D a, Pos3D b){
		return new Pos3D((a.x+b.x)/2,(a.y+b.y)/2,(a.z+b.z)/2); 
	}
	public String toPovrayVector(){
		return "<"+x+","+y+","+z+">"; 
	}

	public String toString(){
		return x+" "+y+" "+z; 
	}
	
	public void normalize(){
		double no=Math.sqrt(x*x+y*y+z*z);
		this.x=x/no; 
		this.y=y/no; 
		this.z=z/no; 
	}
	
	public double produitScalaire(Pos3D B){
		return this.x*B.x+this.y*B.y+this.z*B.z; 
	}
	
	public static Pos3D produitvectoriel(Pos3D u,Pos3D v){
		return new Pos3D(u.y*v.z-u.z*v.y,u.z*v.x-u.x*v.z,u.x*v.y-u.y*v.x); 
	}

	/** Tourne de alpha selon l'axe Z, puis de beta selan l'axe Y **/
	public Pos3D rotate(CoupleDAngles rot){
		double alpha=rot.getAlpha(); 
		double beta=rot.getBeta(); 
		double xp=x*Math.cos(alpha)-y*Math.sin(alpha); 
		double yp=x*Math.sin(alpha)+y*Math.cos(alpha); 
		double xpp=xp*Math.cos(beta)-z*Math.sin(beta); 
		double zp=xp*Math.sin(beta)+z*Math.cos(beta);
		return new Pos3D(xpp,yp,zp); 
	}

	/** Effectue la rotation inverse de celle indiquee dans rot **/
	public Pos3D rotateInverse(CoupleDAngles rot)
	{
		double alpha=rot.getAlpha(); 
		double beta=rot.getBeta(); 
		double xp=x*Math.cos(-beta)-z*Math.sin(-beta); 
		double zp=x*Math.sin(-beta)+z*Math.cos(-beta); 
		double xpp=xp*Math.cos(-alpha)-y*Math.sin(-alpha); 
		double yp=xp*Math.sin(-alpha)+y*Math.cos(-alpha);
		return new Pos3D(xpp,yp,zp); 
	}
	
	public double norme(){
		return Math.sqrt(x*x+y*y+z*z); 
	}
	
	public String rawString(){
		return this.x+" "+this.y+" "+this.z; 
	}
	
	public static void main(String[] args) {
		Pos3D p=new Pos3D(1,1,10);
		CoupleDAngles cda=new CoupleDAngles(Math.PI/2,0); 
		Pos3D p1=p.rotate(cda);
		System.out.println(p); 
		System.out.println(p1); 
		System.out.println(p1.rotateInverse(cda)); 
	}
}
